#include "myMeshHierarchy.h"

char * copyStr(const char *s){
	if (!s) 
		return NULL;
	size_t len = strlen(s)+1;
	void *r = malloc(len);
	//char *newString = new char[len];
	memcpy(r, (void*)s, len);

	return (char*)r;
}

HRESULT myMeshHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *ppNewFrame){
	ppNewFrame = new LPD3DXFRAME;
	ZeroMemory(ppNewFrame, sizeof(D3DXFRAME));
	(*ppNewFrame)->Name = copyStr(Name);
	(*ppNewFrame)->pFrameFirstChild = NULL;
	(*ppNewFrame)->pFrameSibling = NULL;
	(*ppNewFrame)->pMeshContainer = NULL;
	D3DXMatrixIdentity(&((*ppNewFrame)->TransformationMatrix));
	
	return S_OK;
}

HRESULT myMeshHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA *pMeshData, 
    CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, 
    DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, 
	LPD3DXMESHCONTAINER *ppNewMeshContainer){
		
		ppNewMeshContainer = new LPD3DXMESHCONTAINER;
		ZeroMemory(ppNewMeshContainer, sizeof(D3DXMESHCONTAINER));
		(*ppNewMeshContainer)->Name = copyStr(Name);
		if ( D3DXMESHTYPE_MESH != pMeshData->Type ){
			DestroyMeshContainer(*ppNewMeshContainer);
			return E_FAIL;
		}
		(*ppNewMeshContainer)->MeshData.Type = D3DXMESHTYPE_MESH;
		DWORD dwFaces = pMeshData->pMesh->GetNumFaces();
		(*ppNewMeshContainer)->pAdjacency = new DWORD [3*dwFaces];
		memcpy((*ppNewMeshContainer)->pAdjacency, pAdjacency, sizeof(DWORD)*3*dwFaces);
		LPDIRECT3DDEVICE9 d3ddev = NULL;
		pMeshData->pMesh->GetDevice(&d3ddev);
		D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
		if (FAILED(pMeshData->pMesh->GetDeclaration(declaration))){
			DestroyMeshContainer(*ppNewMeshContainer);
			return E_FAIL;
		}
		pMeshData->pMesh->CloneMesh(D3DXMESH_MANAGED, declaration, d3ddev, &((*ppNewMeshContainer)->MeshData.pMesh));
		(*ppNewMeshContainer)->NumMaterials = max(NumMaterials, 1);
		(*ppNewMeshContainer)->pMaterials = new D3DXMATERIAL [(*ppNewMeshContainer)->NumMaterials];
		
		if ( 0 < NumMaterials ) {
			for (DWORD i = 0; i < NumMaterials; i++){
				(*ppNewMeshContainer)->pMaterials[i] = pMaterials[i];
				if (pMaterials[i].pTextureFilename){
					// to be continued...
				}
			}
		}else{
			ZeroMemory((*ppNewMeshContainer)->pMaterials, sizeof(D3DXMATERIAL));
			(*ppNewMeshContainer)->pMaterials[0].MatD3D.Diffuse.r = 1.0f;
			(*ppNewMeshContainer)->pMaterials[0].MatD3D.Diffuse.g = 1.0f;
			(*ppNewMeshContainer)->pMaterials[0].MatD3D.Diffuse.b = 1.0f;
			(*ppNewMeshContainer)->pMaterials[0].MatD3D.Diffuse.a = 1.0f;
			(*ppNewMeshContainer)->pMaterials[0].MatD3D.Specular = (*ppNewMeshContainer)->pMaterials[0].MatD3D.Diffuse;
			(*ppNewMeshContainer)->pMaterials[0].pTextureFilename = NULL;
		}

		if (pSkinInfo){
			(*ppNewMeshContainer)->pSkinInfo = pSkinInfo;
			pSkinInfo->AddRef();
		}else{
			(*ppNewMeshContainer)->pSkinInfo = NULL;
		}

		d3ddev->Release();

		return S_OK;
}

HRESULT myMeshHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree){
	delete [] pFrameToFree->Name;
	delete pFrameToFree;

	return S_OK;
}

HRESULT myMeshHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerToFree){
	delete [] pMeshContainerToFree->Name;
	delete [] pMeshContainerToFree->pAdjacency;
	if (pMeshContainerToFree->MeshData.pMesh)
		pMeshContainerToFree->MeshData.pMesh->Release();
	if (pMeshContainerToFree->pSkinInfo)
		pMeshContainerToFree->pSkinInfo->Release();
	delete [] pMeshContainerToFree->pMaterials;
	delete pMeshContainerToFree;

	return S_OK;
}